# engine.py

import sys
import operator
import itertools

from pyke import knowledge_engine, krb_traceback

def init():
    global Engine
    Engine = knowledge_engine.engine(__file__)

Debug = False

def calc_relevance(cf, relevance):
    r'''Calculates the weighted relevance of a question.

    The weighted relevence is the question relevance modified by the diagnosis
    CF.
    '''
    return cf * relevance

def combine_relevances(relevances):
    r'''Combines the weighted relevances for one question into one value.
    '''
    return max(relevances)

def consult(rule_base, **fact_bases):
    Engine.reset()
    for fb, facts in fact_bases.iteritems():
        # kludge to force the creation of fb in case no facts are present...
        Engine.assert_(fb, "dummy_fact", ())

        for fact_name, value in facts.iteritems():
            Engine.assert_(fb, fact_name, (value,))
    try:
        Engine.activate(rule_base)
        with Engine.prove_goal(
               '%s.diagnosis($disease, ($cf, $questions))' % (rule_base,)) \
          as gen:
            diseases = sorted(((vars['disease'], vars['cf'],
                                sorted(vars['questions'],
                                       key=operator.itemgetter(1),
                                       reverse=True))
                               for vars, _ in gen),
                              key=operator.itemgetter(1),
                              reverse=True)
            individual_relevances = \
              sorted(((category, q_name, calc_relevance(cf, relevance))
                      for _, cf, questions in diseases
                        for (category, q_name), relevance in questions),
                     key=operator.itemgetter(0, 1))
            #print "individual_relevances:", individual_relevances
            questions = sorted(((category, q_name,
                                 combine_relevances(q_and_r[2]
                                                    for q_and_r
                                                     in q_and_relevances))
                                for (category, q_name), q_and_relevances
                                 in itertools.groupby(individual_relevances,
                                      key=operator.itemgetter(0, 1))),
                               key=operator.itemgetter(2),
                               reverse=True)
            #print "questions:", questions
            return diseases, questions
    except Exception:
        # Not sure this is really right long term, but for now ...
        if Debug:
            krb_traceback.print_exc()
            sys.exit(1)
        else:
            raise

